home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / ghostview / ps.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  42KB  |  1,355 lines

  1. /*
  2.  * ps.c -- Postscript scanning and copying routines.
  3.  * Copyright (C) 1992  Timothy O. Theisen
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *   Author: Tim Theisen           Systems Programmer
  20.  * Internet: tim@cs.wisc.edu       Department of Computer Sciences
  21.  *     UUCP: uwvax!tim             University of Wisconsin-Madison
  22.  *    Phone: (608)262-0438         1210 West Dayton Street
  23.  *      FAX: (608)262-9777         Madison, WI   53706
  24.  */
  25.  
  26. #include <stdio.h>
  27. #ifndef SEEK_SET
  28. #define SEEK_SET 0
  29. #endif
  30. #ifndef BUFSIZ
  31. #define BUFSIZ 1024
  32. #endif
  33. #include <ctype.h>
  34. #include <X11/Xos.h>        /* #includes the appropriate <string.h> */
  35. #include "ps.h"
  36.  
  37. #ifdef BSD4_2
  38. #define memset(a,b,c) bzero(a,c)
  39. #endif
  40.  
  41. /* length calculates string length at compile time */
  42. /* can only be used with character constants */
  43. #define length(a) (sizeof(a)-1)
  44. #define iscomment(a, b)    (strncmp(a, b, length(b)) == 0)
  45.  
  46.     /* list of standard paper sizes from Adobe's PPD. */
  47.  
  48. struct documentmedia papersizes[] = {
  49.     "Letter",         612,  792,
  50.     "LetterSmall",     612,  792,
  51.     "Tabloid",         792, 1224,
  52.     "Ledger",        1224,  792,
  53.     "Legal",         612, 1008,
  54.     "Statement",     396,  612,
  55.     "Executive",     540,  720,
  56.     "A3",         842, 1190,
  57.     "A4",         595,  842,
  58.     "A4Small",         595,  842,
  59.     "A5",         420,  595,
  60.     "B4",         729, 1032,
  61.     "B5",         516,  729,
  62.     "Folio",         612,  936,
  63.     "Quarto",         610,  780,
  64.     "10x14",         720, 1008,
  65.     NULL,           0,    0
  66. };
  67.  
  68.  
  69. static char *readline();
  70. static char *gettextline();
  71. static char *gettext();
  72. static int  blank();
  73.  
  74. /*
  75.  *    psscan -- scan the PostScript file for document structuring comments.
  76.  *
  77.  *    This scanner is designed to retrieve the information necessary for
  78.  *    the ghostview previewer.  It will scan files that conform to any
  79.  *    version (1.0, 2.0, 2.1, or 3.0) of the document structuring conventions.
  80.  *    It does not really care which version of comments the file contains.
  81.  *    (The comments are largely upward compatible.)  It will scan a number
  82.  *    of non-conforming documents.  (You could have part of the document
  83.  *    conform to V2.0 and the rest conform to V3.0.  It would be similar
  84.  *    to the DC-2 1/2+, it would look funny but it can still fly.)
  85.  *
  86.  *    This routine returns a pointer to the document structure.
  87.  *    The structure contains the information relevant to previewing.
  88.  *      These include EPSF flag (to tell if the file is a encapsulated figure),
  89.  *      Page Media (for the Page Size), Bounding Box (to minimize backing
  90.  *      pixmap size or determine window size for encapsulated PostScript), 
  91.  *      Orientation of Paper (for default transformation matrix), and
  92.  *      Page Order.  The title and CreationDate are also retrieved to
  93.  *      help identify the document.
  94.  *
  95.  *      The following comments are examined:
  96.  *
  97.  *      Header section: 
  98.  *      Must start with %!PS-Adobe-.  Version numbers ignored.
  99.  *
  100.  *      %!PS-Adobe-* [EPSF-*]
  101.  *      %%BoundingBox: <int> <int> <int> <int>|(atend)
  102.  *      %%CreationDate: <textline>
  103.  *      %%Orientation: Portrait|Landscape|(atend)
  104.  *      %%Pages: <uint> [<int>]|(atend)
  105.  *      %%PageOrder: Ascend|Descend|Special|(atend)
  106.  *      %%Title: <textline>
  107.  *      %%DocumentMedia: <text> <real> <real> <real> <text> <text>
  108.  *      %%DocumentPageSizes: <text>
  109.  *      %%EndComments
  110.  *
  111.  *      Note: Either the 3.0 or 2.0 syntax for %%Pages is accepted.
  112.  *            Also either the 2.0 %%DocumentPageSizes or the 3.0
  113.  *            %%DocumentMedia comments are accepted as well.
  114.  *
  115.  *      The header section ends either explicitly with %%EndComments or
  116.  *      implicitly with any line that does not begin with %X where X is
  117.  *      a not whitespace character.
  118.  *
  119.  *      If the file is encapsulated PostScript the optional Preview section
  120.  *      is next:
  121.  *
  122.  *      %%BeginPreview
  123.  *      %%EndPreview
  124.  *
  125.  *      This section explicitly begins and ends with the above comments.
  126.  *
  127.  *      Next the Defaults section for version 3 page defaults:
  128.  *
  129.  *      %%BeginDefaults
  130.  *      %%PageBoundingBox: <int> <int> <int> <int>
  131.  *      %%PageOrientation: Portrait|Landscape
  132.  *      %%PageMedia: <text>
  133.  *      %%EndDefaults
  134.  *
  135.  *      This section explicitly begins and ends with the above comments.
  136.  *
  137.  *      The prolog section either explicitly starts with %%BeginProlog or
  138.  *      implicitly with any nonblank line.
  139.  *
  140.  *      %%BeginProlog
  141.  *      %%EndProlog
  142.  *
  143.  *      The Prolog should end with %%EndProlog, however the proglog implicitly
  144.  *      ends when %%BeginSetup, %%Page, %%Trailer or %%EOF are encountered.
  145.  *
  146.  *      The Setup section is where the version 2 page defaults are found.
  147.  *      This section either explicitly begins with %%BeginSetup or implicitly
  148.  *      with any nonblank line after the Prolog.
  149.  *
  150.  *      %%BeginSetup
  151.  *      %%PageBoundingBox: <int> <int> <int> <int>
  152.  *      %%PageOrientation: Portrait|Landscape
  153.  *      %%PaperSize: <text>
  154.  *      %%EndSetup
  155.  *
  156.  *      The Setup should end with %%EndSetup, however the setup implicitly
  157.  *      ends when %%Page, %%Trailer or %%EOF are encountered.
  158.  *
  159.  *      Next each page starts explicitly with %%Page and ends implicitly with
  160.  *      %%Page or %%Trailer or %%EOF.  The following comments are recognized:
  161.  *
  162.  *      %%Page: <text> <uint>
  163.  *      %%PageBoundingBox: <int> <int> <int> <int>|(atend)
  164.  *      %%PageOrientation: Portrait|Landscape
  165.  *      %%PageMedia: <text>
  166.  *      %%PaperSize: <text>
  167.  *
  168.  *      The tralier section start explicitly with %%Trailer and end with %%EOF.
  169.  *      The following comment are examined with the proper (atend) notation
  170.  *      was used in the header:
  171.  *
  172.  *      %%Trailer
  173.  *      %%BoundingBox: <int> <int> <int> <int>|(atend)
  174.  *      %%Orientation: Portrait|Landscape|(atend)
  175.  *      %%Pages: <uint> [<int>]|(atend)
  176.  *      %%PageOrder: Ascend|Descend|Special|(atend)
  177.  *      %%EOF
  178.  *
  179.  *
  180.  *  + A DC-3 received severe damage to one of its wings.  The wing was a total
  181.  *    loss.  There was no replacement readily available, so the mechanic
  182.  *    installed a wing from a DC-2.
  183.  */
  184.  
  185. struct document *
  186. psscan(file)
  187.     FILE *file;
  188. {
  189.     struct document *doc;
  190.     int bb_set = NONE;
  191.     int pages_set = NONE;
  192.     int page_order_set = NONE;
  193.     int orientation_set = NONE;
  194.     int page_bb_set = NONE;
  195.     int page_media_set = NONE;
  196.     int preread;        /* flag which tells the readline isn't needed */
  197.     int i;
  198.     unsigned int maxpages = 0;
  199.     unsigned int nextpage = 1;    /* Next expected page */
  200.     unsigned int thispage;
  201.     int ignore = 0;        /* whether to ignore page ordinals */
  202.     char *label;
  203.     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
  204.     char text[PSLINELENGTH];    /* Temporary storage for text */
  205.     long position;        /* Position of the current line */
  206.     unsigned int line_len;     /* Length of the current line */
  207.     unsigned int section_len;    /* Place to accumulate the section length */
  208.     char *next_char;        /* 1st char after text returned by gettext() */
  209.     char *cp;
  210.     struct documentmedia *dmp;
  211.  
  212.     rewind(file);
  213.     if (readline(line, sizeof line, file, &position, &line_len) == NULL) {
  214.     fprintf(stderr, "Warning: empty file.\n");
  215.     return(NULL);
  216.     }
  217.  
  218.     /* Header comments */
  219.  
  220.     if (iscomment(line,"%!PS-Adobe-")) {
  221.     doc = (struct document *) malloc(sizeof(struct document));
  222.     if (doc == NULL) {
  223.         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  224.         exit(-1);
  225.     }
  226.     memset(doc, 0, sizeof(struct document));
  227.     sscanf(line, "%*s %s", text);
  228.     doc->epsf = iscomment(text, "EPSF-");
  229.     doc->beginheader = position;
  230.     section_len = line_len;
  231.     } else {
  232.     return(NULL);
  233.     }
  234.  
  235.     preread = 0;
  236.     while (preread || readline(line, sizeof line, file, &position, &line_len)) {
  237.     if (!preread) section_len += line_len;
  238.     preread = 0;
  239.     if (iscomment(line, "%%EndComments") ||
  240.         line[0] != '%' ||
  241.         (!isprint(line[1]) || line[1] == ' ' ||
  242.          line[1] == '\t' || line[1] == '\n')) {
  243.         break;
  244.     } else if (!iscomment(line, "%%")) {
  245.         /* Do nothing */
  246.     } else if (doc->title == NULL && iscomment(line+2, "Title:")) {
  247.         doc->title = gettextline(line+length("%%Title:"));
  248.     } else if (doc->date == NULL && iscomment(line+2, "CreationDate:")) {
  249.         doc->date = gettextline(line+length("%%CreationDate:"));
  250.     } else if (bb_set == NONE && iscomment(line+2, "BoundingBox:")) {
  251.         sscanf(line+length("%%BoundingBox:"), "%s", text);
  252.         if (strcmp(text, "(atend)") == 0) {
  253.         bb_set = ATEND;
  254.         } else {
  255.         if (sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
  256.                &(doc->boundingbox[LLX]),
  257.                &(doc->boundingbox[LLY]),
  258.                &(doc->boundingbox[URX]),
  259.                &(doc->boundingbox[URY])) == 4)
  260.             bb_set = 1;
  261.         else {
  262.             float fllx, flly, furx, fury;
  263.             if (sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
  264.                    &fllx, &flly, &furx, &fury) == 4) {
  265.             bb_set = 1;
  266.             doc->boundingbox[LLX] = fllx;
  267.             doc->boundingbox[LLY] = flly;
  268.             doc->boundingbox[URX] = furx;
  269.             doc->boundingbox[URY] = fury;
  270.             if (fllx < doc->boundingbox[LLX])
  271.                 doc->boundingbox[LLX]--;
  272.             if (flly < doc->boundingbox[LLY])
  273.                 doc->boundingbox[LLY]--;
  274.             if (furx > doc->boundingbox[URX])
  275.                 doc->boundingbox[URX]++;
  276.             if (fury > doc->boundingbox[URY])
  277.                 doc->boundingbox[URY]++;
  278.             }
  279.         }
  280.         }
  281.     } else if (orientation_set == NONE &&
  282.            iscomment(line+2, "Orientation:")) {
  283.         sscanf(line+length("%%Orientation:"), "%s", text);
  284.         if (strcmp(text, "(atend)") == 0) {
  285.         orientation_set = ATEND;
  286.         } else if (strcmp(text, "Portrait") == 0) {
  287.         doc->orientation = PORTRAIT;
  288.         orientation_set = 1;
  289.         } else if (strcmp(text, "Landscape") == 0) {
  290.         doc->orientation = LANDSCAPE;
  291.         orientation_set = 1;
  292.         }
  293.     } else if (page_order_set == NONE && iscomment(line+2, "PageOrder:")) {
  294.         sscanf(line+length("%%PageOrder:"), "%s", text);
  295.         if (strcmp(text, "(atend)") == 0) {
  296.         page_order_set = ATEND;
  297.         } else if (strcmp(text, "Ascend") == 0) {
  298.         doc->pageorder = ASCEND;
  299.         page_order_set = 1;
  300.         } else if (strcmp(text, "Descend") == 0) {
  301.         doc->pageorder = DESCEND;
  302.         page_order_set = 1;
  303.         } else if (strcmp(text, "Special") == 0) {
  304.         doc->pageorder = SPECIAL;
  305.         page_order_set = 1;
  306.         }
  307.     } else if (pages_set == NONE && iscomment(line+2, "Pages:")) {
  308.         sscanf(line+length("%%Pages:"), "%s", text);
  309.         if (strcmp(text, "(atend)") == 0) {
  310.         pages_set = ATEND;
  311.         } else {
  312.         switch (sscanf(line+length("%%Pages:"), "%d %d",
  313.                    &maxpages, &i)) {
  314.             case 2:
  315.             if (page_order_set == NONE) {
  316.                 if (i == -1) {
  317.                 doc->pageorder = DESCEND;
  318.                 page_order_set = 1;
  319.                 } else if (i == 0) {
  320.                 doc->pageorder = SPECIAL;
  321.                 page_order_set = 1;
  322.                 } else if (i == 1) {
  323.                 doc->pageorder = ASCEND;
  324.                 page_order_set = 1;
  325.                 }
  326.             }
  327.             case 1:
  328.             doc->pages = (struct page *) calloc(maxpages,
  329.                             sizeof(struct page));
  330.             if (doc->pages == NULL) {
  331.                 fprintf(stderr,
  332.                     "Fatal Error: Dynamic memory exhausted.\n");
  333.                 exit(-1);
  334.             }
  335.         }
  336.         }
  337.     } else if (doc->nummedia == NONE &&
  338.            iscomment(line+2, "DocumentMedia:")) {
  339.         float w, h;
  340.         doc->media = (struct documentmedia *)
  341.              malloc(sizeof (struct documentmedia));
  342.         if (doc->media == NULL) {
  343.         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  344.         exit(-1);
  345.         }
  346.         doc->media[0].name = gettext(line+length("%%DocumentMedia:"),
  347.                      &next_char);
  348.         if (doc->media[0].name != NULL) {
  349.         if (sscanf(next_char, "%f %f", &w, &h) == 2) {
  350.             doc->media[0].width = w + 0.5;
  351.             doc->media[0].height = h + 0.5;
  352.         }
  353.         if (doc->media[0].width != 0 && doc->media[0].height != 0)
  354.             doc->nummedia = 1;
  355.         else
  356.             free(doc->media[0].name);
  357.         }
  358.         preread=1;
  359.         while (readline(line, sizeof line, file, &position, &line_len) &&
  360.            iscomment(line, "%%+")) {
  361.         section_len += line_len;
  362.         doc->media = (struct documentmedia *)
  363.                  realloc(doc->media,
  364.                      (doc->nummedia+1)*
  365.                      sizeof (struct documentmedia));
  366.         if (doc->media == NULL) {
  367.             fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  368.             exit(-1);
  369.         }
  370.         doc->media[doc->nummedia].name = gettext(line+length("%%+"),
  371.                              &next_char);
  372.         if (doc->media[doc->nummedia].name != NULL) {
  373.             if (sscanf(next_char, "%f %f", &w, &h) == 2) {
  374.             doc->media[doc->nummedia].width = w + 0.5;
  375.             doc->media[doc->nummedia].height = h + 0.5;
  376.             }
  377.             if (doc->media[doc->nummedia].width != 0 &&
  378.             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  379.             else
  380.             free(doc->media[doc->nummedia].name);
  381.         }
  382.         }
  383.         section_len += line_len;
  384.         if (doc->nummedia != 0) doc->default_page_media = doc->media;
  385.     } else if (doc->nummedia == NONE &&
  386.            iscomment(line+2, "DocumentPaperSizes:")) {
  387.  
  388.         doc->media = (struct documentmedia *)
  389.              malloc(sizeof (struct documentmedia));
  390.         if (doc->media == NULL) {
  391.         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  392.         exit(-1);
  393.         }
  394.         doc->media[0].name = gettext(line+length("%%DocumentPaperSizes:"),
  395.                      &next_char);
  396.         if (doc->media[0].name != NULL) {
  397.         doc->media[0].width = 0;
  398.         doc->media[0].height = 0;
  399.         for (dmp=papersizes; dmp->name != NULL; dmp++) {
  400.             /* Note: Paper size comment uses down cased paper size
  401.              * name.  Case insensitive compares are only used for
  402.              * PaperSize comments.
  403.              */
  404.             if (strcasecmp(doc->media[0].name, dmp->name) == 0) {
  405.             free(doc->media[0].name);
  406.             doc->media[0].name =
  407.                 (char *)malloc(strlen(dmp->name)+1);
  408.             if (doc->media[0].name == NULL) {
  409.                 fprintf(stderr,
  410.                     "Fatal Error: Dynamic memory exhausted.\n");
  411.                 exit(-1);
  412.             }
  413.             strcpy(doc->media[0].name, dmp->name);
  414.             doc->media[0].width = dmp->width;
  415.             doc->media[0].height = dmp->height;
  416.             break;
  417.             }
  418.         }
  419.         if (doc->media[0].width != 0 && doc->media[0].height != 0)
  420.             doc->nummedia = 1;
  421.         else
  422.             free(doc->media[0].name);
  423.         }
  424.         while (cp = gettext(next_char, &next_char)) {
  425.         doc->media = (struct documentmedia *)
  426.                  realloc(doc->media,
  427.                      (doc->nummedia+1)*
  428.                      sizeof (struct documentmedia));
  429.         if (doc->media == NULL) {
  430.             fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  431.             exit(-1);
  432.         }
  433.         doc->media[doc->nummedia].name = cp;
  434.         doc->media[doc->nummedia].width = 0;
  435.         doc->media[doc->nummedia].height = 0;
  436.         for (dmp=papersizes; dmp->name != NULL; dmp++) {
  437.             /* Note: Paper size comment uses down cased paper size
  438.              * name.  Case insensitive compares are only used for
  439.              * PaperSize comments.
  440.              */
  441.             if (strcasecmp(doc->media[doc->nummedia].name,
  442.                    dmp->name) == 0) {
  443.             free(doc->media[doc->nummedia].name);
  444.             doc->media[doc->nummedia].name =
  445.                 (char *)malloc(strlen(dmp->name)+1);
  446.             if (doc->media[doc->nummedia].name == NULL) {
  447.                 fprintf(stderr,
  448.                     "Fatal Error: Dynamic memory exhausted.\n");
  449.                 exit(-1);
  450.             }
  451.             strcpy(doc->media[doc->nummedia].name, dmp->name);
  452.             doc->media[doc->nummedia].name = dmp->name;
  453.             doc->media[doc->nummedia].width = dmp->width;
  454.             doc->media[doc->nummedia].height = dmp->height;
  455.             break;
  456.             }
  457.         }
  458.         if (doc->media[doc->nummedia].width != 0 &&
  459.             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  460.         else
  461.             free(doc->media[doc->nummedia].name);
  462.         }
  463.         preread=1;
  464.         while (readline(line, sizeof line, file, &position, &line_len) &&
  465.            iscomment(line, "%%+")) {
  466.         section_len += line_len;
  467.         next_char = line + length("%%+");
  468.         while (cp = gettext(next_char, &next_char)) {
  469.             doc->media = (struct documentmedia *)
  470.                  realloc(doc->media,
  471.                      (doc->nummedia+1)*
  472.                      sizeof (struct documentmedia));
  473.             if (doc->media == NULL) {
  474.             fprintf(stderr,
  475.                 "Fatal Error: Dynamic memory exhausted.\n");
  476.             exit(-1);
  477.             }
  478.             doc->media[doc->nummedia].name = cp;
  479.             doc->media[doc->nummedia].width = 0;
  480.             doc->media[doc->nummedia].height = 0;
  481.             for (dmp=papersizes; dmp->name != NULL; dmp++) {
  482.             /* Note: Paper size comment uses down cased paper size
  483.              * name.  Case insensitive compares are only used for
  484.              * PaperSize comments.
  485.              */
  486.             if (strcasecmp(doc->media[doc->nummedia].name,
  487.                    dmp->name) == 0) {
  488.                 doc->media[doc->nummedia].width = dmp->width;
  489.                 doc->media[doc->nummedia].height = dmp->height;
  490.                 break;
  491.             }
  492.             }
  493.             if (doc->media[doc->nummedia].width != 0 &&
  494.             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  495.             else
  496.             free(doc->media[doc->nummedia].name);
  497.         }
  498.         }
  499.         section_len += line_len;
  500.         if (doc->nummedia != 0) doc->default_page_media = doc->media;
  501.     }
  502.     }
  503.  
  504.     if (iscomment(line, "%%EndComments")) {
  505.     readline(line, sizeof line, file, &position, &line_len);
  506.     section_len += line_len;
  507.     }
  508.     doc->endheader = position;
  509.     doc->lenheader = section_len - line_len;
  510.  
  511.     /* Optional Preview comments for encapsulated PostScript files */ 
  512.  
  513.     while (blank(line) &&
  514.        readline(line, sizeof line, file, &position, &line_len)) {
  515.     }
  516.  
  517.     if (doc->epsf && iscomment(line, "%%BeginPreview")) {
  518.     doc->beginpreview = position;
  519.     section_len = line_len;
  520.     while (readline(line, sizeof line, file, &position, &line_len) &&
  521.            !iscomment(line, "%%EndPreview")) {
  522.         section_len += line_len;
  523.     }
  524.     section_len += line_len;
  525.     readline(line, sizeof line, file, &position, &line_len);
  526.     section_len += line_len;
  527.     doc->endpreview = position;
  528.     doc->lenpreview = section_len - line_len;
  529.     }
  530.  
  531.     /* Page Defaults for Version 3.0 files */
  532.  
  533.     while (blank(line) &&
  534.        readline(line, sizeof line, file, &position, &line_len)) {
  535.     }
  536.  
  537.     if (iscomment(line, "%%BeginDefaults")) {
  538.     doc->begindefaults = position;
  539.     section_len = line_len;
  540.     while (readline(line, sizeof line, file, &position, &line_len) &&
  541.            !iscomment(line, "%%EndDefaults")) {
  542.         section_len += line_len;
  543.         if (!iscomment(line, "%%")) {
  544.         /* Do nothing */
  545.         } else if (doc->default_page_orientation == NONE &&
  546.         iscomment(line+2, "PageOrientation:")) {
  547.         sscanf(line+length("%%PageOrientation:"), "%s", text);
  548.         if (strcmp(text, "Portrait") == 0) {
  549.             doc->default_page_orientation = PORTRAIT;
  550.         } else if (strcmp(text, "Landscape") == 0) {
  551.             doc->default_page_orientation = LANDSCAPE;
  552.         }
  553.         } else if (page_media_set == NONE &&
  554.                iscomment(line+2, "PageMedia:")) {
  555.         cp = gettext(line+length("%%PageMedia:"), NULL);
  556.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  557.             if (strcmp(cp, dmp->name) == 0) {
  558.             doc->default_page_media = dmp;
  559.             page_media_set = 1;
  560.             break;
  561.             }
  562.         }
  563.         free(cp);
  564.         } else if (page_bb_set == NONE &&
  565.                iscomment(line+2, "PageBoundingBox:")) {
  566.         if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  567.                &(doc->default_page_boundingbox[LLX]),
  568.                &(doc->default_page_boundingbox[LLY]),
  569.                &(doc->default_page_boundingbox[URX]),
  570.                &(doc->default_page_boundingbox[URY])) == 4)
  571.             page_bb_set = 1;
  572.         else {
  573.             float fllx, flly, furx, fury;
  574.             if (sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
  575.                    &fllx, &flly, &furx, &fury) == 4) {
  576.             page_bb_set = 1;
  577.             doc->default_page_boundingbox[LLX] = fllx;
  578.             doc->default_page_boundingbox[LLY] = flly;
  579.             doc->default_page_boundingbox[URX] = furx;
  580.             doc->default_page_boundingbox[URY] = fury;
  581.             if (fllx < doc->default_page_boundingbox[LLX])
  582.                 doc->default_page_boundingbox[LLX]--;
  583.             if (flly < doc->default_page_boundingbox[LLY])
  584.                 doc->default_page_boundingbox[LLY]--;
  585.             if (furx > doc->default_page_boundingbox[URX])
  586.                 doc->default_page_boundingbox[URX]++;
  587.             if (fury > doc->default_page_boundingbox[URY])
  588.                 doc->default_page_boundingbox[URY]++;
  589.             }
  590.         }
  591.         }
  592.     }
  593.     section_len += line_len;
  594.     readline(line, sizeof line, file, &position, &line_len);
  595.     section_len += line_len;
  596.     doc->enddefaults = position;
  597.     doc->lendefaults = section_len - line_len;
  598.     }
  599.  
  600.     /* Document Prolog */
  601.  
  602.     while (blank(line) &&
  603.        readline(line, sizeof line, file, &position, &line_len)) {
  604.     }
  605.  
  606.     if (!iscomment(line, "%%BeginSetup") && !iscomment(line, "%%Page:") &&
  607.     !iscomment(line, "%%Trailer") && !iscomment(line, "%%EOF")) {
  608.     doc->beginprolog = position;
  609.     section_len = line_len;
  610.     preread = 1;
  611.  
  612.     while ((preread ||
  613.         readline(line, sizeof line, file, &position, &line_len)) &&
  614.            !iscomment(line, "%%EndProlog") &&
  615.            !iscomment(line, "%%BeginSetup") &&
  616.            !iscomment(line, "%%Page:") && !iscomment(line, "%%Trailer") &&
  617.            !iscomment(line, "%%EOF")) {
  618.         if (!preread) section_len += line_len;
  619.         preread = 0;
  620.     }
  621.     section_len += line_len;
  622.     if (iscomment(line, "%%EndProlog")) {
  623.         readline(line, sizeof line, file, &position, &line_len);
  624.         section_len += line_len;
  625.     }
  626.     doc->endprolog = position;
  627.     doc->lenprolog = section_len - line_len;
  628.     }
  629.  
  630.     /* Document Setup,  Page Defaults found here for Version 2 files */
  631.  
  632.     while (blank(line) &&
  633.        readline(line, sizeof line, file, &position, &line_len)) {
  634.     }
  635.  
  636.     if (!iscomment(line, "%%Page:") && !iscomment(line, "%%Trailer") &&
  637.     !iscomment(line, "%%EOF")) {
  638.     doc->beginsetup = position;
  639.     section_len = line_len;
  640.     preread = 1;
  641.     while ((preread ||
  642.         readline(line, sizeof line, file, &position, &line_len)) &&
  643.            !iscomment(line, "%%EndSetup") && !iscomment(line, "%%Page:") &&
  644.            !iscomment(line, "%%Trailer") && !iscomment(line, "%%EOF")) {
  645.         if (!preread) section_len += line_len;
  646.         preread = 0;
  647.         if (!iscomment(line, "%%")) {
  648.         /* Do nothing */
  649.         } else if (doc->default_page_orientation == NONE &&
  650.         iscomment(line+2, "PageOrientation:")) {
  651.         sscanf(line+length("%%PageOrientation:"), "%s", text);
  652.         if (strcmp(text, "Portrait") == 0) {
  653.             doc->default_page_orientation = PORTRAIT;
  654.         } else if (strcmp(text, "Landscape") == 0) {
  655.             doc->default_page_orientation = LANDSCAPE;
  656.         }
  657.         } else if (page_media_set == NONE &&
  658.                iscomment(line+2, "PaperSize:")) {
  659.         cp = gettext(line+length("%%PaperSize:"), NULL);
  660.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  661.             /* Note: Paper size comment uses down cased paper size
  662.              * name.  Case insensitive compares are only used for
  663.              * PaperSize comments.
  664.              */
  665.             if (strcasecmp(cp, dmp->name) == 0) {
  666.             doc->default_page_media = dmp;
  667.             page_media_set = 1;
  668.             break;
  669.             }
  670.         }
  671.         free(cp);
  672.         } else if (page_bb_set == NONE &&
  673.                iscomment(line+2, "PageBoundingBox:")) {
  674.         if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  675.                &(doc->default_page_boundingbox[LLX]),
  676.                &(doc->default_page_boundingbox[LLY]),
  677.                &(doc->default_page_boundingbox[URX]),
  678.                &(doc->default_page_boundingbox[URY])) == 4)
  679.             page_bb_set = 1;
  680.         else {
  681.             float fllx, flly, furx, fury;
  682.             if (sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
  683.                    &fllx, &flly, &furx, &fury) == 4) {
  684.             page_bb_set = 1;
  685.             doc->default_page_boundingbox[LLX] = fllx;
  686.             doc->default_page_boundingbox[LLY] = flly;
  687.             doc->default_page_boundingbox[URX] = furx;
  688.             doc->default_page_boundingbox[URY] = fury;
  689.             if (fllx < doc->default_page_boundingbox[LLX])
  690.                 doc->default_page_boundingbox[LLX]--;
  691.             if (flly < doc->default_page_boundingbox[LLY])
  692.                 doc->default_page_boundingbox[LLY]--;
  693.             if (furx > doc->default_page_boundingbox[URX])
  694.                 doc->default_page_boundingbox[URX]++;
  695.             if (fury > doc->default_page_boundingbox[URY])
  696.                 doc->default_page_boundingbox[URY]++;
  697.             }
  698.         }
  699.         }
  700.     }
  701.     section_len += line_len;
  702.     if (iscomment(line, "%%EndSetup")) {
  703.         readline(line, sizeof line, file, &position, &line_len);
  704.         section_len += line_len;
  705.     }
  706.     doc->endsetup = position;
  707.     doc->lensetup = section_len - line_len;
  708.     }
  709.  
  710.     /* Individual Pages */
  711.  
  712.     while (blank(line) &&
  713.        readline(line, sizeof line, file, &position, &line_len)) {
  714.     }
  715.  
  716. newpage:
  717.     while (iscomment(line, "%%Page:")) {
  718.     if (maxpages == 0) {
  719.         maxpages = 1;
  720.         doc->pages = (struct page *) calloc(maxpages, sizeof(struct page));
  721.         if (doc->pages == NULL) {
  722.         fprintf(stderr,
  723.             "Fatal Error: Dynamic memory exhausted.\n");
  724.         exit(-1);
  725.         }
  726.     }
  727.     label = gettext(line+length("%%Page:"), &next_char);
  728.     if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
  729.     if (nextpage == 1) {
  730.         ignore = thispage != 1;
  731.     }
  732.     if (!ignore && thispage != nextpage) {
  733.         free(label);
  734.         doc->numpages--;
  735.         goto continuepage;
  736.     }
  737.     nextpage++;
  738.     if (doc->numpages == maxpages) {
  739.         maxpages++;
  740.         doc->pages = (struct page *)
  741.              realloc(doc->pages, maxpages*sizeof (struct page));
  742.         if (doc->pages == NULL) {
  743.         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  744.         exit(-1);
  745.         }
  746.     }
  747.     memset(&(doc->pages[doc->numpages]), 0, sizeof(struct page));
  748.     page_bb_set = NONE;
  749.     doc->pages[doc->numpages].label = label;
  750.     doc->pages[doc->numpages].begin = position;
  751.     section_len = line_len;
  752. continuepage:
  753.     while (readline(line, sizeof line, file, &position, &line_len) &&
  754.            !iscomment(line, "%%Page:") && !iscomment(line, "%%Trailer") &&
  755.            !iscomment(line, "%%EOF")) {
  756.         section_len += line_len;
  757.         if (!iscomment(line, "%%")) {
  758.         /* Do nothing */
  759.         } else if (doc->pages[doc->numpages].orientation == NONE &&
  760.         iscomment(line+2, "PageOrientation:")) {
  761.         sscanf(line+length("%%PageOrientation:"), "%s", text);
  762.         if (strcmp(text, "Portrait") == 0) {
  763.             doc->pages[doc->numpages].orientation = PORTRAIT;
  764.         } else if (strcmp(text, "Landscape") == 0) {
  765.             doc->pages[doc->numpages].orientation = LANDSCAPE;
  766.         }
  767.         } else if (doc->pages[doc->numpages].media == NULL &&
  768.                iscomment(line+2, "PageMedia:")) {
  769.         cp = gettext(line+length("%%PageMedia:"), NULL);
  770.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  771.             if (strcmp(cp, dmp->name) == 0) {
  772.             doc->pages[doc->numpages].media = dmp;
  773.             break;
  774.             }
  775.         }
  776.         free(cp);
  777.         } else if (doc->pages[doc->numpages].media == NULL &&
  778.                iscomment(line+2, "PaperSize:")) {
  779.         cp = gettext(line+length("%%PaperSize:"), NULL);
  780.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  781.             /* Note: Paper size comment uses down cased paper size
  782.              * name.  Case insensitive compares are only used for
  783.              * PaperSize comments.
  784.              */
  785.             if (strcasecmp(cp, dmp->name) == 0) {
  786.             doc->pages[doc->numpages].media = dmp;
  787.             break;
  788.             }
  789.         }
  790.         free(cp);
  791.         } else if ((page_bb_set == NONE || page_bb_set == ATEND) &&
  792.                iscomment(line+2, "PageBoundingBox:")) {
  793.         sscanf(line+length("%%PageBoundingBox:"), "%s", text);
  794.         if (strcmp(text, "(atend)") == 0) {
  795.             page_bb_set = ATEND;
  796.         } else {
  797.             if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  798.                 &(doc->pages[doc->numpages].boundingbox[LLX]),
  799.                 &(doc->pages[doc->numpages].boundingbox[LLY]),
  800.                 &(doc->pages[doc->numpages].boundingbox[URX]),
  801.                 &(doc->pages[doc->numpages].boundingbox[URY])) == 4)
  802.             if (page_bb_set == NONE) page_bb_set = 1;
  803.             else {
  804.             float fllx, flly, furx, fury;
  805.             if (sscanf(line+length("%%PageBoundingBox:"),
  806.                    "%f %f %f %f",
  807.                    &fllx, &flly, &furx, &fury) == 4) {
  808.                 if (page_bb_set == NONE) page_bb_set = 1;
  809.                 doc->pages[doc->numpages].boundingbox[LLX] = fllx;
  810.                 doc->pages[doc->numpages].boundingbox[LLY] = flly;
  811.                 doc->pages[doc->numpages].boundingbox[URX] = furx;
  812.                 doc->pages[doc->numpages].boundingbox[URY] = fury;
  813.                 if (fllx <
  814.                     doc->pages[doc->numpages].boundingbox[LLX])
  815.                 doc->pages[doc->numpages].boundingbox[LLX]--;
  816.                 if (flly <
  817.                     doc->pages[doc->numpages].boundingbox[LLY])
  818.                 doc->pages[doc->numpages].boundingbox[LLY]--;
  819.                 if (furx >
  820.                     doc->pages[doc->numpages].boundingbox[URX])
  821.                 doc->pages[doc->numpages].boundingbox[URX]++;
  822.                 if (fury >
  823.                     doc->pages[doc->numpages].boundingbox[URY])
  824.                 doc->pages[doc->numpages].boundingbox[URY]++;
  825.             }
  826.             }
  827.         }
  828.         }
  829.     }
  830.     section_len += line_len;
  831.     doc->pages[doc->numpages].end = position;
  832.     doc->pages[doc->numpages].len = section_len - line_len;
  833.     doc->numpages++;
  834.     }
  835.  
  836.     /* Document Trailer */
  837.  
  838.     doc->begintrailer = position;
  839.     section_len = line_len;
  840.  
  841.     preread = 1;
  842.     while ((preread ||
  843.         readline(line, sizeof line, file, &position, &line_len)) &&
  844.        !iscomment(line, "%%EOF")) {
  845.     if (!preread) section_len += line_len;
  846.     preread = 0;
  847.     if (!iscomment(line, "%%")) {
  848.         /* Do nothing */
  849.     } else if (iscomment(line+2, "Page:")) {
  850.         free(gettext(line+length("%%Page:"), &next_char));
  851.         if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
  852.         if (!ignore && thispage == nextpage) {
  853.         if (doc->numpages > 0) {
  854.             doc->pages[doc->numpages-1].end = position;
  855.             doc->pages[doc->numpages-1].len += section_len - line_len;
  856.         }
  857.         goto newpage;
  858.         }
  859.     } else if (bb_set == ATEND && iscomment(line+2, "BoundingBox:")) {
  860.         if (sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
  861.                &(doc->boundingbox[LLX]),
  862.                &(doc->boundingbox[LLY]),
  863.                &(doc->boundingbox[URX]),
  864.                &(doc->boundingbox[URY])) != 4) {
  865.         float fllx, flly, furx, fury;
  866.         if (sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
  867.                &fllx, &flly, &furx, &fury) == 4) {
  868.             doc->boundingbox[LLX] = fllx;
  869.             doc->boundingbox[LLY] = flly;
  870.             doc->boundingbox[URX] = furx;
  871.             doc->boundingbox[URY] = fury;
  872.             if (fllx < doc->boundingbox[LLX])
  873.             doc->boundingbox[LLX]--;
  874.             if (flly < doc->boundingbox[LLY])
  875.             doc->boundingbox[LLY]--;
  876.             if (furx > doc->boundingbox[URX])
  877.             doc->boundingbox[URX]++;
  878.             if (fury > doc->boundingbox[URY])
  879.             doc->boundingbox[URY]++;
  880.         }
  881.         }
  882.     } else if (orientation_set == ATEND &&
  883.            iscomment(line+2, "Orientation:")) {
  884.         sscanf(line+length("%%Orientation:"), "%s", text);
  885.         if (strcmp(text, "Portrait") == 0) {
  886.         doc->orientation = PORTRAIT;
  887.         } else if (strcmp(text, "Landscape") == 0) {
  888.         doc->orientation = LANDSCAPE;
  889.         }
  890.     } else if (page_order_set == ATEND && iscomment(line+2, "PageOrder:")) {
  891.         sscanf(line+length("%%PageOrder:"), "%s", text);
  892.         if (strcmp(text, "Ascend") == 0) {
  893.         doc->pageorder = ASCEND;
  894.         } else if (strcmp(text, "Descend") == 0) {
  895.         doc->pageorder = DESCEND;
  896.         } else if (strcmp(text, "Special") == 0) {
  897.         doc->pageorder = SPECIAL;
  898.         }
  899.     } else if (pages_set == ATEND && iscomment(line+2, "Pages:")) {
  900.         if (sscanf(line+length("%%Pages:"), "%*u %d", &i) == 1) {
  901.         if (page_order_set == NONE) {
  902.             if (i == -1) doc->pageorder = DESCEND;
  903.             else if (i == 0) doc->pageorder = SPECIAL;
  904.             else if (i == 1) doc->pageorder = ASCEND;
  905.         }
  906.         }
  907.     }
  908.     }
  909.     section_len += line_len;
  910.     if (iscomment(line, "%%EOF")) {
  911.     readline(line, sizeof line, file, &position, &line_len);
  912.     section_len += line_len;
  913.     }
  914.     doc->endtrailer = position;
  915.     doc->lentrailer = section_len - line_len;
  916.  
  917.     section_len = line_len;
  918.     preread = 1;
  919.     while (preread ||
  920.        readline(line, sizeof line, file, &position, &line_len)) {
  921.     if (!preread) section_len += line_len;
  922.     preread = 0;
  923.     if (iscomment(line, "%%Page:")) {
  924.         free(gettext(line+length("%%Page:"), &next_char));
  925.         if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
  926.         if (!ignore && thispage == nextpage) {
  927.         doc->pages[doc->numpages-1].end = position;
  928.         doc->pages[doc->numpages-1].len += doc->lentrailer +
  929.                            section_len - line_len;
  930.         goto newpage;
  931.         }
  932.     }
  933.     }
  934.     return doc;
  935. }
  936.  
  937. /*
  938.  *    psfree -- free dynamic storage associated with document structure.
  939.  */
  940.  
  941. void
  942. psfree(doc)
  943.     struct document *doc;
  944. {
  945.     int i;
  946.  
  947.     if (doc) {
  948.     for (i=0; i<doc->numpages; i++) {
  949.         if (doc->pages[i].label) free(doc->pages[i].label);
  950.     }
  951.     for (i=0; i<doc->nummedia; i++) {
  952.         if (doc->media[i].name) free(doc->media[i].name);
  953.     }
  954.     if (doc->title) free(doc->title);
  955.     if (doc->date) free(doc->date);
  956.     if (doc->pages) free(doc->pages);
  957.     if (doc->media) free(doc->media);
  958.     free(doc);
  959.     }
  960. }
  961.  
  962. /*
  963.  * gettextine -- skip over white space and return the rest of the line.
  964.  *               If the text begins with '(' return the text string
  965.  *         using gettext().
  966.  */
  967.  
  968. static char *
  969. gettextline(line)
  970.     char *line;
  971. {
  972.     char *cp;
  973.  
  974.     while (*line && (*line == ' ' || *line == '\t')) line++;
  975.     if (*line == '(') {
  976.     return gettext(line, NULL);
  977.     } else {
  978.     if (strlen(line) == 0) return NULL;
  979.     cp = (char *) malloc(strlen(line));
  980.     if (cp == NULL) {
  981.         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  982.         exit(-1);
  983.     }
  984.     strncpy(cp, line, strlen(line)-1);
  985.     cp[strlen(line)-1] = '\0';
  986.     return cp;
  987.     }
  988. }
  989.  
  990. /*
  991.  *    gettext -- return the next text string on the line.
  992.  *           return NULL if nothing is present.
  993.  */
  994.  
  995. static char *
  996. gettext(line, next_char)
  997.     char *line;
  998.     char **next_char;
  999. {
  1000.     char text[PSLINELENGTH];    /* Temporary storage for text */
  1001.     char *cp;
  1002.     int quoted=0;
  1003.  
  1004.     while (*line && (*line == ' ' || *line == '\t')) line++;
  1005.     cp = text;
  1006.     if (*line == '(') {
  1007.     int level = 0;
  1008.     quoted=1;
  1009.     line++;
  1010.     while (*line && !(*line == ')' && level == 0 )) {
  1011.         if (*line == '\\') {
  1012.         if (*(line+1) == 'n') {
  1013.             *cp++ = '\n';
  1014.             line += 2;
  1015.         } else if (*(line+1) == 'r') {
  1016.             *cp++ = '\r';
  1017.             line += 2;
  1018.         } else if (*(line+1) == 't') {
  1019.             *cp++ = '\t';
  1020.             line += 2;
  1021.         } else if (*(line+1) == 'b') {
  1022.             *cp++ = '\b';
  1023.             line += 2;
  1024.         } else if (*(line+1) == 'f') {
  1025.             *cp++ = '\f';
  1026.             line += 2;
  1027.         } else if (*(line+1) == '\\') {
  1028.             *cp++ = '\\';
  1029.             line += 2;
  1030.         } else if (*(line+1) == '(') {
  1031.             *cp++ = '(';
  1032.             line += 2;
  1033.         } else if (*(line+1) == ')') {
  1034.             *cp++ = ')';
  1035.             line += 2;
  1036.         } else if (*(line+1) >= '0' && *(line+1) <= '9') {
  1037.             if (*(line+2) >= '0' && *(line+2) <= '9') {
  1038.             if (*(line+3) >= '0' && *(line+3) <= '9') {
  1039.                 *cp++ = ((*(line+1) - '0')*8 + *(line+2) - '0')*8 +
  1040.                     *(line+3) - '0';
  1041.                 line += 4;
  1042.             } else {
  1043.                 *cp++ = (*(line+1) - '0')*8 + *(line+2) - '0';
  1044.                 line += 3;
  1045.             }
  1046.             } else {
  1047.             *cp++ = *(line+1) - '0';
  1048.             line += 2;
  1049.             }
  1050.         } else {
  1051.             line++;
  1052.             *cp++ = *line++;
  1053.         }
  1054.         } else if (*line == '(') {
  1055.         level++;
  1056.         *cp++ = *line++;
  1057.         } else if (*line == ')') {
  1058.         level--;
  1059.         *cp++ = *line++;
  1060.         } else {
  1061.         *cp++ = *line++;
  1062.         }
  1063.     }
  1064.     } else {
  1065.     while (*line && !(*line == ' ' || *line == '\t' || *line == '\n'))
  1066.         *cp++ = *line++;
  1067.     }
  1068.     *cp = '\0';
  1069.     if (next_char) *next_char = line;
  1070.     if (!quoted && strlen(text) == 0) return NULL;
  1071.     cp = (char *) malloc(strlen(text)+1);
  1072.     if (cp == NULL) {
  1073.     fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  1074.     exit(-1);
  1075.     }
  1076.     strcpy(cp, text);
  1077.     return cp;
  1078. }
  1079.  
  1080. /*
  1081.  *    readline -- Read the next line in the postscript file.
  1082.  *                  Automatically skip over data (as indicated by
  1083.  *                  %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
  1084.  *            comments.)
  1085.  *            Also, skip over included documents (as indicated by
  1086.  *            %%BeginDocument/%%EndDocument comments.)
  1087.  */
  1088.  
  1089. static char *
  1090. readline(line, size, fp, position, line_len)
  1091.     char *line;
  1092.     int size;
  1093.     FILE *fp;
  1094.     long *position;
  1095.     unsigned int *line_len;
  1096. {
  1097.     char text[PSLINELENGTH];    /* Temporary storage for text */
  1098.     char save[PSLINELENGTH];    /* Temporary storage for text */
  1099.     char *cp;
  1100.     unsigned int num;
  1101.     unsigned int nbytes;
  1102.     int i;
  1103.     char buf[BUFSIZ];
  1104.  
  1105.     if (position) *position = ftell(fp);
  1106.     cp = fgets(line, size, fp);
  1107.     if (cp == NULL) line[0] = '\0';
  1108.     *line_len = strlen(line);
  1109.     if (iscomment(line, "%%BeginDocument:")) {
  1110.     strcpy(save, line+7);
  1111.     while (readline(line, size, fp, NULL, &nbytes) &&
  1112.            !iscomment(line, "%%EndDocument")) {
  1113.         *line_len += nbytes;
  1114.     }
  1115.     *line_len += nbytes;
  1116.     strcpy(line, save);
  1117.     } else if (iscomment(line, "%%BeginFeature:")) {
  1118.     strcpy(save, line+7);
  1119.     while (readline(line, size, fp, NULL, &nbytes) &&
  1120.            !iscomment(line, "%%EndFeature")) {
  1121.         *line_len += nbytes;
  1122.     }
  1123.     *line_len += nbytes;
  1124.     strcpy(line, save);
  1125.     } else if (iscomment(line, "%%BeginFile:")) {
  1126.     strcpy(save, line+7);
  1127.     while (readline(line, size, fp, NULL, &nbytes) &&
  1128.            !iscomment(line, "%%EndFile")) {
  1129.         *line_len += nbytes;
  1130.     }
  1131.     *line_len += nbytes;
  1132.     strcpy(line, save);
  1133.     } else if (iscomment(line, "%%BeginFont:")) {
  1134.     strcpy(save, line+7);
  1135.     while (readline(line, size, fp, NULL, &nbytes) &&
  1136.            !iscomment(line, "%%EndFont")) {
  1137.         *line_len += nbytes;
  1138.     }
  1139.     *line_len += nbytes;
  1140.     strcpy(line, save);
  1141.     } else if (iscomment(line, "%%BeginProcSet:")) {
  1142.     strcpy(save, line+7);
  1143.     while (readline(line, size, fp, NULL, &nbytes) &&
  1144.            !iscomment(line, "%%EndProcSet")) {
  1145.         *line_len += nbytes;
  1146.     }
  1147.     *line_len += nbytes;
  1148.     strcpy(line, save);
  1149.     } else if (iscomment(line, "%%BeginResource:")) {
  1150.     strcpy(save, line+7);
  1151.     while (readline(line, size, fp, NULL, &nbytes) &&
  1152.            !iscomment(line, "%%EndResource")) {
  1153.         *line_len += nbytes;
  1154.     }
  1155.     *line_len += nbytes;
  1156.     strcpy(line, save);
  1157.     } else if (iscomment(line, "%%BeginData:")) {
  1158.     text[0] = '\0';
  1159.     strcpy(save, line+7);
  1160.     if (sscanf(line+length("%%BeginData:"), "%d %*s %s", &num, text) >= 1) {
  1161.         if (strcmp(text, "Lines") == 0) {
  1162.         for (i=0; i < num; i++) {
  1163.             cp = fgets(line, size, fp);
  1164.             *line_len += cp ? strlen(line) : 0;
  1165.         }
  1166.         } else {
  1167.         while (num > BUFSIZ) {
  1168.             fread(buf, sizeof (char), BUFSIZ, fp);
  1169.             *line_len += BUFSIZ;
  1170.             num -= BUFSIZ;
  1171.         }
  1172.         fread(buf, sizeof (char), num, fp);
  1173.         *line_len += num;
  1174.         }
  1175.     }
  1176.     while (readline(line, size, fp, NULL, &nbytes) &&
  1177.            !iscomment(line, "%%EndData")) {
  1178.         *line_len += nbytes;
  1179.     }
  1180.     *line_len += nbytes;
  1181.     strcpy(line, save);
  1182.     } else if (iscomment(line, "%%BeginBinary:")) {
  1183.     strcpy(save, line+7);
  1184.     if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
  1185.         while (num > BUFSIZ) {
  1186.         fread(buf, sizeof (char), BUFSIZ, fp);
  1187.         *line_len += BUFSIZ;
  1188.         num -= BUFSIZ;
  1189.         }
  1190.         fread(buf, sizeof (char), num, fp);
  1191.         *line_len += num;
  1192.     }
  1193.     while (readline(line, size, fp, NULL, &nbytes) &&
  1194.            !iscomment(line, "%%EndBinary")) {
  1195.         *line_len += nbytes;
  1196.     }
  1197.     *line_len += nbytes;
  1198.     strcpy(line, save);
  1199.     }
  1200.     return cp;
  1201. }
  1202.  
  1203. /*
  1204.  *    pscopy -- copy lines of Postscript from a section of one file
  1205.  *          to another file.
  1206.  *                Automatically switch to binary copying whenever
  1207.  *                %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
  1208.  *          comments are encountered.
  1209.  */
  1210.  
  1211. void
  1212. pscopy(from, to, begin, end)
  1213.     FILE *from;
  1214.     FILE *to;
  1215.     long begin;            /* set negative to avoid initial seek */
  1216.     long end;
  1217. {
  1218.     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
  1219.     char text[PSLINELENGTH];    /* Temporary storage for text */
  1220.     unsigned int num;
  1221.     int i;
  1222.     char buf[BUFSIZ];
  1223.  
  1224.     if (begin >= 0) fseek(from, begin, SEEK_SET);
  1225.     while (ftell(from) < end) {
  1226.  
  1227.     fgets(line, sizeof line, from);
  1228.     fputs(line, to);
  1229.  
  1230.     if (iscomment(line, "%%BeginData:")) {
  1231.         text[0] = '\0';
  1232.         if (sscanf(line+length("%%BeginData:"),
  1233.                "%d %*s %s", &num, text) >= 1) {
  1234.         if (strcmp(text, "Lines") == 0) {
  1235.             for (i=0; i < num; i++) {
  1236.             fgets(line, sizeof line, from);
  1237.             fputs(line, to);
  1238.             }
  1239.         } else {
  1240.             while (num > BUFSIZ) {
  1241.             fread(buf, sizeof (char), BUFSIZ, from);
  1242.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1243.             num -= BUFSIZ;
  1244.             }
  1245.             fread(buf, sizeof (char), num, from);
  1246.             fwrite(buf, sizeof (char), num, to);
  1247.         }
  1248.         }
  1249.     } else if (iscomment(line, "%%BeginBinary:")) {
  1250.         if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
  1251.         while (num > BUFSIZ) {
  1252.             fread(buf, sizeof (char), BUFSIZ, from);
  1253.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1254.             num -= BUFSIZ;
  1255.         }
  1256.         fread(buf, sizeof (char), num, from);
  1257.         fwrite(buf, sizeof (char), num, to);
  1258.         }
  1259.     }
  1260.     }
  1261. }
  1262.  
  1263. /*
  1264.  *    pscopyuntil -- copy lines of Postscript from a section of one file
  1265.  *               to another file until a particular comment is reached.
  1266.  *                     Automatically switch to binary copying whenever
  1267.  *                     %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
  1268.  *               comments are encountered.
  1269.  */
  1270.  
  1271. char *
  1272. pscopyuntil(from, to, begin, end, comment)
  1273.     FILE *from;
  1274.     FILE *to;
  1275.     long begin;            /* set negative to avoid initial seek */
  1276.     long end;
  1277. #if NeedFunctionPrototypes
  1278.     const
  1279. #endif
  1280.     char *comment;
  1281. {
  1282.     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
  1283.     char text[PSLINELENGTH];    /* Temporary storage for text */
  1284.     unsigned int num;
  1285.     int comment_length;
  1286.     int i;
  1287.     char buf[BUFSIZ];
  1288.     char *cp;
  1289.  
  1290.     comment_length = strlen(comment);
  1291.     if (begin >= 0) fseek(from, begin, SEEK_SET);
  1292.     while (ftell(from) < end) {
  1293.  
  1294.     fgets(line, sizeof line, from);
  1295.  
  1296.     /* iscomment cannot be used here,
  1297.      * because comment_length is not known at compile time. */
  1298.     if (strncmp(line, comment, comment_length) == 0) {
  1299.         cp = (char *) malloc(strlen(line)+1);
  1300.         if (cp == NULL) {
  1301.         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  1302.         exit(-1);
  1303.         }
  1304.         strcpy(cp, line);
  1305.         return cp;
  1306.     }
  1307.     fputs(line, to);
  1308.     if (iscomment(line, "%%BeginData:")) {
  1309.         text[0] = '\0';
  1310.         if (sscanf(line+length("%%BeginData:"),
  1311.                "%d %*s %s", &num, text) >= 1) {
  1312.         if (strcmp(text, "Lines") == 0) {
  1313.             for (i=0; i < num; i++) {
  1314.             fgets(line, sizeof line, from);
  1315.             fputs(line, to);
  1316.             }
  1317.         } else {
  1318.             while (num > BUFSIZ) {
  1319.             fread(buf, sizeof (char), BUFSIZ, from);
  1320.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1321.             num -= BUFSIZ;
  1322.             }
  1323.             fread(buf, sizeof (char), num, from);
  1324.             fwrite(buf, sizeof (char), num, to);
  1325.         }
  1326.         }
  1327.     } else if (iscomment(line, "%%BeginBinary:")) {
  1328.         if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
  1329.         while (num > BUFSIZ) {
  1330.             fread(buf, sizeof (char), BUFSIZ, from);
  1331.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1332.             num -= BUFSIZ;
  1333.         }
  1334.         fread(buf, sizeof (char), num, from);
  1335.         fwrite(buf, sizeof (char), num, to);
  1336.         }
  1337.     }
  1338.     }
  1339.     return NULL;
  1340. }
  1341.  
  1342. /*
  1343.  *    blank -- determine whether the line contains nothing but whitespace.
  1344.  */
  1345.  
  1346. static int
  1347. blank(line)
  1348.     char *line;
  1349. {
  1350.     char *cp = line;
  1351.  
  1352.     while (*cp == ' ' || *cp == '\t') cp++;
  1353.     return *cp == '\n' || (*cp == '%' && (line[0] != '%' || line[1] != '%'));
  1354. }
  1355.